package org.zxp.thread.lock;

import org.junit.Test;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @program: zxp-thread-test
 * @description:  ReentrantLock功能使用
 * @author: X-Pacific zhang
 * @create: 2019-05-11 16:28
 **/
public class ReentrantLockTest {
    private static Lock lock = new ReentrantLock();
    private static Condition condition = lock.newCondition();
    private static int num = 0;

    private static int incr() {
        int a = 0;
        lock.lock();
        num += 1;
        lock.unlock();
        return num;
    }

    public static void main(String[] args) throws InterruptedException {
//        for (int i = 0; i < 3; i++) {
//            new Thread(() -> {
//                System.out.println(incr());
//            }).start();
//        }
//        System.out.println(num);
        lock.lock();
        lock.lock();


        lock.unlock();
        System.out.println();
        //必须全部unlock才能解锁
    }


    /**
     * 测试lockInterruptibly
     * “当前等待获取锁的线程”（注意不是已经获得锁的线程）interrupt时会直接抛出异常（lock.lockInterruptibly();抛出异常）
     */
    @Test
        public void testLockInterruptibly() throws InterruptedException {
        Thread thread1 = new Thread(() -> {
            lock.lock();
            try {
                Thread.sleep(1000L);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            lock.unlock();
        });
        thread1.start();
        Thread thread2 = new Thread(() -> {
            try {
                lock.lockInterruptibly();
                lock.unlock();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        thread2.start();
        Thread.sleep(100L);
        System.out.println(thread2.getState());
//        thread2.interrupt();
        Thread.sleep(4000L);
    }


    /**
     * 测试tryLock
     */
    @Test
    public void testTryLock() throws InterruptedException {
        Thread thread1 = new Thread(() -> {
            lock.lock();
            try {
                Thread.sleep(1000L);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            lock.unlock();
        });
        thread1.start();
        Thread thread2 = new Thread(() -> {
            boolean result = lock.tryLock();
            System.out.println("thread2获取锁的结果："+result);
            if(result) {
                lock.unlock();
            }
        });
        thread2.start();
        Thread.sleep(500L);
        System.out.println(thread2.getState());
        Thread.sleep(4000L);
    }


    /**
     * 测试tryLock超时
     */
    @Test
    public void testTryLock2() throws InterruptedException {
        Thread thread1 = new Thread(() -> {
            lock.lock();
            try {
                Thread.sleep(1000L);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            lock.unlock();
        });
        thread1.start();
        Thread thread2 = new Thread(() -> {
            boolean result = false;
            try {
                //尝试100毫秒获取锁 结果：失败返回false
//                result = lock.tryLock(100l, TimeUnit.MILLISECONDS);
                //尝试1500毫秒获取锁 结果：成功返回true
                result = lock.tryLock(1500l, TimeUnit.MILLISECONDS);
                System.out.println("thread2获取锁的结果："+result);
                if(result) {
                    lock.unlock();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        thread2.start();
        Thread.sleep(500L);
        System.out.println(thread2.getState());
        Thread.sleep(4000L);
    }

    /**
     * 测试ReentrantLock是否是乐观锁
     */
    @Test
    public void testReentrantLockType() throws InterruptedException {
        Thread thread1 = new Thread(() -> {
            lock.lock();
            System.out.println("thread1进来");
            try {
                Thread.sleep(2000L);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            lock.unlock();
        });
        thread1.start();

        Thread thread2 = new Thread(() -> {
            lock.lock();
            System.out.println("thread2进来");
            lock.unlock();
        });
        thread2.start();
        Thread.sleep(1000L);
        System.out.println(thread1.getState());
        System.out.println(thread2.getState());
        Thread.sleep(4000L);
    }


    private volatile static boolean flag = false;
    private Object condition2 = new Object();

    /**
     * 测试condition
     */
    @Test
    public void testCondition(){
        new Thread(() -> {
            lock.lock();
            try{
                while(!flag){
                    System.out.println("未开通，等待其他线程开通");
                    try {
                        condition.await();//调用这个也会把当前锁释放，当前线程阻塞在这里等待通知
//                        condition2.wait();//这种必须得获得condition2的锁才可以
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("得到通知，已经开通");
            }finally {
                lock.unlock();
            }
        }).start();
        long sleepTime = 2000L;
        System.out.println("等待："+sleepTime + "后…");
        try {
            Thread.sleep(sleepTime);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        new Thread(() -> {
            lock.lock();
            try{
                condition.signalAll();
//                condition2.notifyAll();//这种必须得获得condition2的锁才可以
                flag = true;
            }finally {
                lock.unlock();
            }
        }).start();


        try {
            Thread.sleep(3000L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }



}
